<?php

namespace app\bll;

use app\validate\HomeMenu as ValidateHomeMenu;
use BlueM\Tree;
use BlueM\Tree\Serializer\HierarchicalTreeJsonSerializer;
use core\attribute\Template;
use Exception;
use support\Db;
use Throwable;

/**
 * 前台导航菜单
 */
class HomeMenu
{

    /**
     * 
     * 查找单个菜单信息
     * @param integer $id
     * @param integer $siteid
     * @return array
     */
    public function find(int $id, int $siteid): array
    {
        $data =  Db::table('frame_home_menu')
            ->where('id', '=', $id)
            ->where('siteid', '=', $siteid)
            ->first();
        return $data === null ? [] : get_object_vars($data);
    }
    /**
     * 查询某分类下菜单
     *
     * @param integer $siteid
     * @return array
     */
    public function select(int $cid, int $siteid): array
    {
        return  Db::table('frame_home_menu')
            ->where('siteid', '=', $siteid)
            ->where('cid', '=', $cid)
            ->orderByRaw('sort asc, id asc')
            ->get()
            ->map(function ($value) {
                return (array)$value;
            })
            ->toArray();
    }

    /**
     * 添加菜单
     *
     * @param array $data
     * @return integer
     */
    public function add(array $data): int
    {
        $validateHomeMenu = new ValidateHomeMenu();
        if (!$validateHomeMenu->check($data)) {
            throw new Exception($validateHomeMenu->getSimpleError());
        }


        return Db::table('frame_home_menu')
            ->insertGetId($data);
    }

    /**
     * 编辑菜单
     *
     * @param integer $id
     * @param integer $siteid
     * @param array $data
     * @return int
     */
    public function edit(int $id, int $siteid, array $data): int
    {
        $data['siteid']   = $siteid;
        $validateHomeMenu = new ValidateHomeMenu();
        if (!$validateHomeMenu->check($data)) {
            throw new Exception($validateHomeMenu->getSimpleError());
        }


        return Db::table('frame_home_menu')
            ->where('id', '=', $id)
            ->where('siteid', '=', $siteid)
            ->update($data);
    }

    /**
     * 删除菜单
     *
     * @param integer $id
     * @param integer $siteid
     */
    public function delete(int $id, int $siteid)
    {

        try {
            $menuinfo = $this->find($id, $siteid);
            $childids = $this->descendantsAndSelfIds($id, $menuinfo['cid'], $siteid);
            Db::table('frame_home_menu')
                ->whereIn('id', $childids)
                ->where('siteid', '=', $siteid)
                ->delete();
        } catch (Exception $ex) {
            throw $ex;
        }
    }


    /**
     * 排序
     *
     * @param integer $id
     * @param float $sort
     * @param integer $siteid
     * @return integer
     */
    public function sort(int $id, float $sort, int $siteid): int
    {
        return  Db::table('frame_home_menu')
            ->where('id', '=', $id)
            ->where('siteid', '=', $siteid)
            ->update([
                'sort' => $sort
            ]);
    }



    /**
     * 某节点的子集ID
     *
     * @param integer $id
     * @param integer $cid
     * @param integer $siteid
     * @return void
     */
    public function descendantsAndSelfIds(int $id, int $cid, int $siteid)
    {
        $tree = new Tree(
            $this->select($cid, $siteid),
            [
                'rootId'         => 0,
                'id'             => 'id',
                'parent'         => 'pid'
            ]
        );
        $node = $tree->getNodeById($id);
        $descendantsPlusSelf = $node->getDescendantsAndSelf();
        $ids = [];
        foreach ($descendantsPlusSelf as $key => $node) {
            $ids[] = $node->id;
        }
        return $ids;
    }



    /**
     * 层级输出
     *
     * @param integer $cid
     * @param integer $siteid
     * @param boolean $tojson
     * @return string|array|Tree
     */
    #[Template]
    public function cascader(int $cid, int $siteid, bool $tojson = true): string|array|Tree
    {

        $tree = new Tree(
            $this->select($cid, $siteid),
            [
                'rootId'         => 0,
                'id'             => 'id',
                'parent'         => 'pid',
                'jsonSerializer' => new HierarchicalTreeJsonSerializer()
            ]
        );

        return $tojson ? json_encode($tree, JSON_UNESCAPED_UNICODE) : $tree;
    }
}
